perm filename IPSER.MA4[IP,SYS] blob
sn#707711 filedate 1983-04-20 generic text, type T, neo UTF8
title IPSer
subttl provan
search f,s
search NetDef ; get network definitions
search MacTen ; search *after* NetDef
sall
$reloc
$high
XP VIPSer,1 ; first IP version
comment \
this module contains the support routines for the internet protocol
as defined in RFC-791 and support for its companion protocol, the
internet control message protocol as defined in RFC-792.
\
subttl defintions describing an IP leader
; see RFC-791 for details of this header.
.IpVer==4 ; version of IP that this module understands
.IpTTL==MSL ; make MSL the time to live for our packets (1 min.)
IPMax==:↑d576 ; recommended maximum size of IP message
IpLen==:5 ; number of words in an IP leader (not
; including options).
$low ; define the storage needed
IpIBHd: block NBHLen ; header in case ICMP has to send this
; leader back out.
IpIBuf: block IpLen ; words needed for header
; the following block is used and removed under ScnOff.
IpOBuf: block NBHLen+IpLen ; buffer for forming IP leaders
; for output.
$high ; back to protected code
IpPnt: point 8,IpIBuf ; pointer to start loading the
; header block from the stream.
; define the actual header fields. position is the bit position of the
; left most bit.
;
; name word position width
DefFd. IPVers, 0, 0, 4 ; version of this message's protocol
DefFd. IpIHL, 0, 4, 4 ; internet header length (32 bit words)
DefFd. IPTOS, 0, 8, 8 ; type of service
DefFd. IPTLen, 0, 16, 16 ; total length (8 bit bytes)
DefFd. IpId, 1, 0, 16 ; identification
DefFd. IpFrgF, 1, 16, 16 ; entire fragment field
IP%MF==<1←↑d13> ; more fragments after this one if set.
DefFd. IpFOff, 1, 19, 13 ; fragment offset (8 octets)
DefFd. IpTTL, 2, 0, 8 ; time to live
DefFd. IpProt, 2, 8, 8 ; protocol of next level
DefFd. IpHChk, 2, 16, 16 ; header checksum
DefFd. IpSA, 3, 0, 32 ; source address
DefFd. IpDA, 4, 0, 32 ; destination address
subttl other definitions for IP header
; flags in flag field of the time-stamp IP option. these bits are
; not explicitly defined in the protocol, but they agree with the
; definitions for this field after we've made sure not to try to
; handle values in this field we do not understand. these flags
; are kept in the right half of S while processing a time-stamp option.
IP%Adr==1 ; each timestamp is preceeded
; by an internet address.
IP%Set==2 ; the internet addresses in the
; option are preset: a host
; should only fill in the
; time-stamp field if it finds
; its host number in the
; internet address field.
; flags found in left half of S put in the left half of S to spot various
; conditions which are detected during option processing.
IP$Str==1b17 ; strict routing was indicated.
; targetting MUST be directly
; to the next host in the route
; (next host is already loaded
; into IPDA.)
IP$Rou==1b16 ; used internally in option
; parsing to distinguich
; between a source route and a
; record route option.
IPAddr:: ArpAdr!ThSite## ; get our site number
subttl FDB - fragmentation data block
;++
;
; block containing data to allow a fragmented message to
; be reassembled.
;
;--
;;!------------------------------------|------------------------------------!
;;! last FDB in chain | next FDB in chain !
;;!------------------------------------|------------------------------------!
;;! source address of this fragment !
;;!------------------------------------|------------------------------------!
;;! destination address of this fragment !
;;!------------------------------------|------------------------------------!
;;! protocol of this fragment | message ID of this message !
;;!------------------------------------|------------------------------------!
;;! bit mask: one bit for each 8 byte group, set if !
;;! this group has arrived. group 0 is represented !
;;! by low order bit of the first word. the number !
;;! of words in the mask depends on the maximum message !
;;! size we are prepared to accept. !
;;!------------------------------------|------------------------------------!
;;! total length of message in bytes, if known !
;;!------------------------------------|------------------------------------!
;;! count of octoctets currently in buffers !
;;!------------------------------------|------------------------------------!
;;! trash | pointer to first buffer !
;;!------------------------------------|------------------------------------!
;;! time to live for this FDB !
;;!------------------------------------|------------------------------------!
bkini. ; initialize allocation mechanism
BkNxt. FDBLst,hlf.wd ;(LH) previous FDB in chain
BkNxt. FDBNxt,hlf.wd ;(RH) next FDB in chain
BkNxt. FDBSou ; source address
BkNxt. FDBDes ; destination address
BkDef. FDBFID ; define a word for the ID of the fragment.
; the ID contains:
BkNxt. FDBPro,hlf.wd ; in the left half, the message protocol
BkNxt. FDBID,hlf.wd ; in the right half, the message ID
BkNxt. FDBMsk,2*ful.wd ; first word of bit mask. one
; bit for each 8 byte group.
BkNxt. FDBLen ; total length of message, if known.
BkNxt. FDBRCt ; number of octoctets actually received.
BkNxt. FDBMes ; pointer to actual buffer chain.
BkOff. FDBMOf ; get offset into block for this, too.
BkNxt. FDBTTL ; time until we discard the fragments
; (decremented in once a second code)
FDBTO==↑d60 ; timeout after one minute.
BkEnd. FDBLen
subttl IpIn - handle an incoming IP message
entry IpIn ; only load if IMPSer calls for this routine
IpIn::
move t1,IpPnt ; get pointer to buffer space.
movei t2,IpLen*4 ; load the number of bytes to get.
stor. t2,NBHCnt,IPIBHd ; save as byte count, this buffer.
ifn FtChck,< ; checksumming
setz p3, ; start the checksumming at zero
>
pushj p,GetLed## ; get the leader and checksum it
jrst NoLead ; not enough words in the stream.
load. t1,IpVers,IpIBuf ; get the version
caie t1,.IPVer ; is it the current version?
jrst BadVer ; no. forget it.
; now read in the options and hold for later
load. t1,IPIHL,IpIBuf ; get length of header in words
subi t1,IPLen ; get words left to be read in leader
jumple t1,IPIn0 ; no options to read
lsh t1,wd2byt ; convert to bytes
pushj p,GetMes## ; read in the options
jrst NoLead ; message ended too soon.
aos IPOpt## ; saw an option
IPIn0: movem t1,IPOptn ; save pointer to options 'til later.
skipg t1 ; any options?
movei t1,IpIBHd ; no. point at input buffer
; header for last buffer, but
; have no first buffer.
hrrm t1,ABfLst(f) ; save last buffer of assembled stream.
hlrz p1,t1 ; get just first buffer number
stor. p1,NBHNxt,IpIBHd ; link to IP in case ICMP has
; to fire this back out.
ifn FtChck,< ; doing checksumming
load. t1,IPHChk,IpIBuf ; get the checksum from the leader
jumpe t1,IPNCk ; this guy doesn't do checksums
; bear in mind that the checksum we now have in P3 has, along with
; all the right stuff, its one's complement. therefore, what
; we really have is <checksum> + -<checksum>, which is 0.
; further, since <checksum> has some bit on (otherwise the
; sender isn't checksuming and we wouldn't be here), it can be
; shown that the brand of one's complement 0 we must have is
; the version with all 1's. if that's what we have, we're ok.
; if not, the checksum failed.
hrrzs p3 ; get just the checksum
caie p3,<1←↑d16>-1 ; magic, as explained above
jrst BadChk ; checksum failed
IPNCk: ; here to skip over the checksum checks because sender is not
; checksumming.
>
subttl now parse options
setzb p3,s ; clear count register and flags
OptnLp: pushj p,NxtByt## ; get next option
jrst OptDun ; no more
hrlzi t4,-OptCnt ; point at options
TryNxt: camn t1,OptNum(t4) ; is this the right option?
jrst @OptDis(t4) ; yes. jump to the processing routine
aobjn t4,TryNxt ; try the next option.
aos IPEUOp## ; we don't understand this option.
OptSkp: pushj p,OptFls## ; flush the option
jrst OptDun ; all done.
jrst OptnLp ; and try the next option
OptDun:
load. t1,IpDA,IpIBuf ; get destination address
came t1,IPAddr ; is it us? (option parsing could
; have changed it, or it was always
; addressed to someone else.)
Not2Us==IpFlsh ; implement this later
jrst Not2Us ; no. do whatever needs doing.
; (i.e., retarget and send it.)
subttl rebuild a fragmented message
load. t1,IpTLen,IpIBuf ; get total length of message
load. t2,IpIHL,IpIBuf ; and length of this header
lsh t2,wd2byt ; convert from words to bytes
sub t1,t2 ; get the length of the data
movem t1,MsgLen(f) ; save this as the length of
; the message.
load. t1,IpSA,IpIBuf ; get source address
load. t2,IpDA,IpIBuf ; and destination address
load. t3,IpID,IpIBuf ; get ID
load. t4,IpProt,IpIBuf ; get protocol
hrl t3,t4 ; put protocol and ID together
skipn p1,FstFDB ; get first FDB.
jrst NoFDB ; none there.
FDLook: cam. t3,FDBID,(p1),n ; is it this message?
cam. t1,FDBSou,(p1),e ; is this our source?
jrst FDLoop ; no. try next FDB.
cam. t2,FDBDes,(p1),n ; and our destination?
jrst FDBFnd ; this is our FDB
FDLoop: load. p1,FDBNxt,(p1) ; get next FDB in chain
jumpn p1,FDLook ; and see if that's what we want.
NoFDB: ; no FDB found for this message.
load. t4,IpFrgF,IpIBuf ; get the fragmentation field
jumpe t4,FrgDun ; if not fragmented, just proceed
aos IPFrag## ; count another fragmented message
pushj p,AllFDB ; get a free FDB in P1.
jrst IPFlsh ; can't get one.
stor. t1,FDBSou,(p1) ; save the source in the FDB
stor. t2,FDBDes,(p1) ; save the destination, too.
stor. t3,FDBID,(p1) ; save the ID/protocol
FDBAdd: load. p2,IPFOff,IpIBuf ; get just the fragment offset
lsh p2,Oct2by ; convert to 8 bit bytes
move t1,MsgLen(f) ; get the length of this packet
add t1,p2 ; add on the fragment's offset
caile t1,IPMax ; is it too large for us?
jrst IpFFDB ; yes. flush it all.
trnn t4,IP%MF ; is this the last fragment?
stor. t1,FDBLen,(p1) ; yes. store total length in FDB
; check to see if there are enough buffers allocated
idivi p2,NBfByt ; P2 = buffer number.
; P3 = bytes in buffer before fragment
movei t4,FDBMOf(p1) ; point at message buffer area
MakeLp: pushj p,NxtOBf ; check next buffer, allocate
; if we must
jrst IpFFDB ; not enough buffers. flush it all.
sojge p2,MakeLp ; allocate as many as we need
; to start.
; now transfer bytes from input stream to fragment buffer
move p2,p3 ; copy of bytes used in this buffer
lsh p2,byt2wd ; change to words used
addi p2,NBHLen(t4) ; point to the word to be filled
hrli p2,(point 8,) ; and make it a pointer.
subi p3,NBfByt ; convert to negative number of
; bytes still allowed in buffer.
push p,t4 ; save current target buffer
FillLp: jsp p4,(p4) ; get next byte from input stream
jrst FillDn ; nothing left. all done filling.
aojle p3,FillL1 ; there's still room here?
pop p,t4 ; get back current buffer
pushj p,NxtOBf ; get the next buffer
jrst IpFFDB ; no free buffers. flush fragment.
push p,t4 ; save new current back on the stack.
move p2,[point 8,NBHLen(t4)] ; point properly at next byte
movni p3,<NBfByt-1> ; reset count
FillL1: idpb t1,p2 ; dump in next slot
jrst FillLp ; and loop until filled
FillDn: pop p,t4 ; get T4 back for the last time
load. t1,FDBLen,(p1) ; get the length
jumpe t1,FillD1 ; haven't seen last fragment yet.
load. t2,NBHNxt,(t4) ; get a pointer to the next buffer.
jumpn t2,FillD1 ; this is not the last buffer
idivi t1,NBfByt ; compute number of bytes in
; last buffer into t2.
skipn t2 ; zero really means "full"
movei t2,NBfByt ; indicate "full"
stor. t2,NBHCnt,(t4) ; save count in buffer header.
FillD1: ; now set all the bits in the mask which we just copied in.
move t4,MsgLen(f) ; get the length of this one again
addi t4,7 ; make sure we round up
lsh t4,-Oct2By ; how many groups of 8 bytes?
load. t1,IpFOff,IpIBuf ; recall the offset start
idivi t1,ful.wd ; which bit in which word of
; the map?
movei t3,1 ; low order bit for first octoctet
lsh t3,(t2) ; shift into the correct position
addi t1,(p1) ; point into this FDB
load. t2,FDBMsk,(t1) ; get the word we're working on
MaskLp: tdon t2,t3 ; set the bit in the word
incr. ,FDBRCt,(p1) ; count this uncounted thingy.
lsh t3,1 ; next bit
jumpn t3,MaskL1 ; still bits to set before i die
stor. t2,FDBMsk,(t1) ; save this word with bits set
aos t1 ; move along to next word
load. t2,FDBMsk,(t1) ; retrieve the next mask
MaskL1: sojg t4,MaskLp ; loop to set all bits
stor. t2,FDBMsk,(t1) ; save the last mask we worked on.
skip. t1,FDBLen,(p1),n ; do we know how long it is yet?
jrst StlFrg ; no. can't be done yet.
addi t1,7 ; round up octoctets
lsh t1,-Oct2By ; divide by 8 to get octoctets
cam. t1,FDBRCt,(p1),le ; and have we got that many yet?
jrst StlFrg ; no. not done yet. just return.
aos IPFDun## ; fragmented message fully rebuilt.
movei p4,InByte## ; input from buffers which are already
; in 32 bit words.
setzm IBfBC(f) ; zero byte count: start fresh.
load. t1,FDBMes,(p1) ; get the buffer.
hrrom t1,IBfThs(f) ; save as current buffer, untouched.
zero. t1,FDBMes,(p1) ; now detach it from the FDB.
load. t1,FDBLen,(p1) ; get total length of message.
movem t1,MsgLen(f) ; copy into DDB
jrst FrgOne ; fragment is reassembled, and
; we just specified how to
; read bytes, so delete the
; FDB and continue.
FDBFnd: load. t4,IpFrgF,IpIBuf ; get frag field
jumpn t4,FDBAdd ; if this is fragmented, add it in.
FrgOne: pushj p,FlsFDB ; throw out existing FDB: we just
; got the entire message at once.
FrgDun: ; here when we have a completed message to pass on.
load. t1,IPSA,IpIBuf ; get the source address
movem t1,RmtAdr(f) ; that's where it came from
load. t1,IPDA,IpIBuf ; get our address
movem t1,LclAdr(f) ; that's the destination
load. t1,IPTOS,IpIBuf ; get the type of service required.
movem t1,SerTyp(f) ; remember it.
load. t1,IPProt,IpIBuf ; get the protocol into t1
movem t1,Protcl(f) ; save that correctly for later, too.
hrlzi t4,-PrtCnt ; set negative counts of protocols
ProtLp: camn t1,PrtNum(t4) ; is this the correct protocol module?
jrst PrtFnd ; found the proper protocol
aobjn t4,ProtLp ; loop over all protocols
aos IPEPrt## ; count seeing a protocol we
; didn't understand.
setzm IpOptn ; the options will get flushed when
; the ICMP message is built.
movei t1,.icDU ; destination unreachable
movei t2,.idPlU ; protocol unreachable
scnoff ; no interrupts allowed
pushj p,RedSn0 ; send out an ICMP telling him
; we don't do that protocol.
pjrst sonppj## ; interupts on and go home.
PrtFnd: pushj p,@PrtHnd(t4) ; yes. call the protocol
; handler for that protocol.
jrst IpFlsh ; clear the IP options.
subttl returns
; error returns before IP options are read in.
BadVer: ; IP version number was not the one we support
aosa IPEVer## ; count version error and skip
NoLead: ; not enough words for a leader
aos IPELed## ; count IP leader error
popj p, ; no other clean up needed
; various returns after IP options have been read in.
BadChk: aos IPEChk## ; count checksum error
IPFlsh: ; ending without error
skipe t1,IpOptn ; any undeleted options?
pushj p,RelBuf## ; yes, delete them.
setzm IpOptn ; make sure options are flushed.
popj p, ; nothing smart yet, just a bad return
; here to flush an FDB and leave incoming processing.
IpFFDB: pushj p,FlsFDB ; flush the FDB
jrst IpFlsh ; now clean up and return.
; here after adding to a fragmented buffer without completing the buffer.
StlFrg: movei t1,FDBTO ; get the timeout time
stor. t1,FDBTTL,(p1) ; reset it
jrst IPFlsh ; and leave
subttl Option handlers
; first define dispatch information for all of them.
; each option has a call on the macro OPT which takes two arguments:
; 1. the option number, in decimal
; 2. the option handling routine. should not use P1-P4.
define Options,
<
opt ( 0,OptDun) ; end of option list (stop processing)
opt ( 1,OptnLp) ; no-op (do nothing)
opt (130,OptSkp) ; security option (ignore for now)
opt (131,OptLSR) ; loose source and record route
opt (137,OptSSR) ; strict source and record route
opt ( 7,OptRec) ; record route
opt (136,OptSkp) ; stream identifier (skip over it)
opt ( 68,OptTim) ; internet time stamp
>
; now define the table of option numbers
define opt( number,dispat ),< ↑d'number > ; just a number for each entry.
OptNum: Options ; expand options
OptCnt==.-OptNum ; get a count of number of options
; and the dispatch vector
define opt( number,dispat ),< z 'dispat > ; dispatch routine
OptDis: Options ; expand the options again
subttl Option parsing code
OptSSR: ; strict source and record route
txo s,IP$Str ; remember we saw strict routing.
; fall into loose code.
OptLSR: ; loose source and record route
load. t1,IPDA,IPIBuf ; get the IP's destination
came t1,IPAddr ; is this us?
jrst OptFls ; no. just skip this option.
txoa s,IP$Rou ; remember to route this
; message to next host in
; source route.
OptRec: txz s,IP$Rou ; just recording route: don't
; save a new source we think
; we found.
pushj p,OptSet ; set up length, etc., in
; standard form.
jrst OptDun ; ran out of option space.
pushj p,OptPos ; position for our entry
jrst OptnLp ; some end of stream that means
; we don't enter an entry.
move t1,IPAddr ; get our address
pushj p,RplWrd## ; replace this word in the
; input stream.
;<not enough bytes. discard and reply with ICMP>
jrst OptDun ; until implemented
movei t2,4 ; four bytes more to account for.
txze s,IP$Rout ; supposed to be routing?
stor. t1,IpDA,IPIBuf ; yes: store the word read as the
; new destination.
; fall into finishing code
; here with T2 = bytes in rewritten fields, T3 with bytes left in
; option (INCLUDING rewritten fields) and T4 an LDB pointer
; to pointer byte.
OptFin: ldb t1,t4 ; get the pointer byte
add t1,t2 ; point past the next address
dpb t1,t4 ; store that back in place
OptEnd: move t1,t3 ; get the number of bytes left
; to be read in this option.
sub t1,t2 ; take into account fields we
; just wrote over.
pushj p,NxtFls## ; skip them
jrst OptDun ; not enough. all done.
jrst OptnLp ; keep parsing.
OptTim: ; internet time stamp
pushj p,OptSet ; read length word.
jrst OptDun ; ran out of space.
pushj p,NxtByt## ; read in overflow field and flags
jrst OptDun ; end of options hit. done.
push p,p2 ; save pointer to overflow
; field in case we need it later.
hrrz s,t1 ; save flags (and overflow field) in S.
sos t2 ; one less to read to position
sos t3 ; one less to read in option
pushj p,OptPos ; position for the field we're after.
jrst OptOvf ; not enough bytes. we need to
; increment overflow field.
OptOvf==OptnLp ; don't do anything for now
pop p,(p) ; we won't need the overflow field.
setz t2, ; no bytes rewritten so far.
txnn s,IP%Adr ; flags say this has internet
; addresses with times?
jrst NoAddr ; no. skip address handling
addi t2,4 ; four bytes are going to be passed
txnn s,IP%Set ; addresses are preset?
jrst ChkAdr ; no. check address, don't
; rewrite it.
move t1,IPAddr ; get our address
pushj p,RplWrd## ; put that in place, get the word read ; value read.
;<error. discard and answer with ICMP>
jrst OptDun ; until implemented
jrst NoAddr ; rejoin checking code
ChkAdr: pushj p,NxtWrd## ; read the internet address
; from stream.
;<error>
jrst OptDun ; until implemented
came t1,IPAddr ; is it our address?
jrst OptEnd ; no. we do nothing for this option
NoAddr: pushj p,MilTim## ; get time since midnight in
; milliseconds.
pushj p,RplWrd## ; put that in place
;<error. discard and respond with ICMP>
jrst OptDun ; until implemented
addi t2,4 ; four more bytes rewritten
jrst OptFin ; update pointer byte and go
; for next option.
subttl subroutines to help option parsing
; set up routine for reading a standard option type.
; returns with
; T2 = number of bytes to read from here to get to field
; "pointer" points to.
; T3 = number of bytes left to be read in this option
; T4 = LDB pointer to pointer field, in case we need to INCR it later.
OptSet:
pushj p,NxtByt## ; read the length
popj p, ; not there. all done.
movei t3,-3(t1) ; save length in "safe" place,
; accounting for type, length
; and pointer bytes.
pushj p,NxtByt## ; get pointer
popj p, ; can't. give up.
move t4,p2 ; save LDP pointer to pointer value.
movei t2,-4(t1) ; make this the number of bytes
; to read to get to our place.
pjrst cpopj1## ; skip return.
; position ourselves to read the field we are being pointed at.
; call with P1-P3 and T2-T4 set up as they are on return from OptSet.
OptPos:
camg t3,t2 ; does it point past end of the
; option?
jrst DntFil ; yes. can't fill anything in
sub t3,t2 ; figure how much will be left after
; we read up to our position.
move t1,t2 ; position number of bytes to read.
pjrst NxtFls## ; skip up to the beginning of
; the field we're pointed at
; and return.
DntFil: move t1,t3 ; number of bytes 'til end of option.
pushj p,NxtFls## ; flush that many bytes
popj p, ; not enough bytes
popj p, ; enough bytes, but we still
; don't have room.
subttl protocol definitions
; define all the protocols we're prepared to handle.
; each definition is a call on the macro Prot with two
; arguments: the protocol number (in decimal) and the routine to call
; when a message of this protocol comes in.
define Prots,
<
prot ( 1,ICMPIn ) ; handle ICMP messages
prot ( 6,TCPIn## ) ; handle TCP messages
; prot (17,UDPIn## ) ; handle UDP
>
; now define the table of protocol numbers
define prot(number,routine),< ↑d'number > ; just put down the number
PrtNum: Prots
PrtCnt==.-PrtNum ; get the count of protocols.
; define the dispatch table
define prot(number,routine),< z 'routine > ; define the routine
PrtHnd: Prots
subttl AllFDB
;++
; Functional description:
;
; allocate an FDB from IMP buffers
;
;
; Calling sequence:
;
; pushj p,AllFDB
; <return here if no buffer available>
; <return here with buffer in P1 and linked into FDB chain>
;
; Input parameters:
;
; none.
;
; Output parameters:
;
; P1 - new buffer.
;
; Implicit inputs:
;
; FDB chain values.
;
; Implicit outputs:
;
; FDB block entries.
;
; Routine value:
;
; returns non-skip if there is no buffer to be had.
;
; Side effects:
;
; allocates a buffer.
;--
AllFDB: pushj p,savt## ; get all T registers
pushj p,BufGet## ; get a fresh buffer.
popj p, ; ACK! can't get one.
move p1,t1 ; position results for return
move t1,FstFDB ; get the first FDB in chain.
stor. t1,FDBNxt,(p1) ; link the old first to this one.
movem p1,FstFDB ; and make us the first.
stor. p1,FDBLst,(t1) ; make us the previous for the next.
movei t1,FDBTO ; get time out value
stor. t1,FDBTTL,(p1) ; and save that, too.
jrst cpopj1## ; and give a good return.
subttl FlsFDB
;++
; Functional description:
;
; return the given FDB and all buffers linked to this FDB to the
; free buffer chain.
;
;
; Calling sequence:
;
; move p1,FDB
; pushj p,FlsFDB
; <always returns here>
;
; Input parameters:
;
; P1 - points to FDB to be discarded.
;
; Output parameters:
;
; none.
;
; Implicit inputs:
;
; data in FDB.
;
; Implicit outputs:
;
; FDB chain.
;
; Routine value:
;
; none.
;
; Side effects:
;
; discard FDB and all attached buffers. closes up FDB chain.
;--
FlsFDB: load. t1,FDBMes,(p1) ; get buffers
pushj p,RelBuf## ; discard entire chain of buffers.
load. t1,FDBNxt,(p1) ; get next FDB in chain.
load. t2,FDBLst,(p1) ; get previous FDB in chain
jumpe t2,[ ; is there a FDB before to me?
movem t1,FstFDB ; no. the next is now first.
jrst FlsFD1 ; continue.
]
stor. t1,FDBNxt,(t2) ; follower now follows predecessor.
FlsFD1: skipe t1 ; if there is a next buffer....
stor. t2,FDBLst,(t1) ; ...its "last" should be updated.
move t1,p1 ; point at this FDB
pjrst BufRel## ; release it.
subttl IpSec
;++
; Functional description:
;
; once a second code for IP. it checks for time outs in
; the fragmentation reassembly chain.
;
;
; Calling sequence:
;
; move t1,<0 to do timeout check, -1 to flush all>
; scnoff
; pushj p,IpSec ; once a second
; <always return here>
;
; Input parameters:
;
; t1 - if 0, IPSEC will decr the timeout field of the FDB and
; delete any FDBs that have been around too long. if
; t1 is -1, all FDBs are flushed.
;
; Output parameters:
;
; none.
;
; Implicit inputs:
;
; FstFdb and the fragmentation chain.
;
; Implicit outputs:
;
; none.
;
; Routine value:
;
; none.
;
; Side effects:
;
; make delete fragment blocks from the fragment chain.
;--
IPSec:: pushj p,save2## ; get two register
move p2,t1 ; save arg in one of them
move p1,FstFdb ; get first FDB in chain
IpSec1: jumpe p1,cpopj## ; return if end of chain
jumpl p2,IpSec3 ; always delete if flushing
decr. ,FDBTTL,(p1),le ; count one more second. expired?
jrst IpSec4 ; no. don't flush
load. t1,FDBMsk,(p1) ; get first word of mask
trnn t1,1 ; first 8 bytes in yet?
jrst IpSec3 ; no. don't send an ICMP error
; because we haven't got the
; next level's leader.
skipa t2,[IpIBHd] ; point at input leader
IpSecL: move t2,t1 ; remember this buffer
load. t1,NBHNxt,(t2) ; get next buffer
jumpn t1,IpSecL ; loop until done.
push p,f ; protect F
setzm IpPDDB+PDBTop ; zero first word of pseudo-DDB
move f,[ xwd IpPDDB+PDBTop,IpPDDB+PDBTop+1 ] ; BLT pointer
blt f,IpPDDB+PDBBot ; clear entire DDB
movei f,IpPDDB ; point at hypothetical start
load. t1,FDBSou,(p1) ; get the source of this fragment
movem t1,RmtAdr(f) ; that's where we're sending the error
pushj p,Target## ; try to get an arpa address.
jrst IpSec2 ; can't get there. just flush
movem t1,NetAdr(f) ; save that for ARPA handler.
move t1,IpAddr ; get our address
movem t1,LclAdr(f) ; we're the one sending this
setzm SndNxt(f) ; clear these two entries so
setzm SndLst(f) ; this message isn't retransmitted.
load. t1,FDBMes,(p1) ; get message pointer
stor. t1,NBHNxt,(t2) ; link this to the current
; input leader.
zero. t1,FDBMes,(p1) ; don't let FlsFDB delete message.
pushj p,FlsFDB ; ditch the FDB now
movei t1,.icTEx ; time exceeded
movei t2,.itFRT ; fragment reassembly time,
; that is.
pushj p,CutSn0 ; cut down message and send it
pop p,f ; get old F back
jrst IpSec4 ; and loop
IpSec2: pop p,f ; restore F
IpSec3: pushj p,FlsFDB ; yes. flush this FDB
IpSec4: load. p1,FDBNxt,(p1) ; get the next one
jrst IpSec1 ; and loop
subttl NxtOBf
;++
; Functional description:
;
; get the next buffer for output. if none allocated, allocate
; one and link it to the last.
;
;
; Calling sequence:
;
; move t4,<pointer to current buffer header>
; pushj p,NxtOBf
; <return here if a buffer was needed, but none available>
; <return here with T4 containing pointer to next buffer>
;
; Input parameters:
;
; T4 - pointer to current buffer header. this can point to the
; FDBMes word.
;
; Output parameters:
;
; T4 - pointer to next buffer
;
; Implicit inputs:
;
; buffer stream.
;
; Implicit outputs:
;
; buffer stream.
;
; Routine value:
;
; returns non-skip if it needed to allocate a buffer, but there
; were none available.
;
; Side effects:
;
; may link another buffer on to the stream.
; clobbers T2 and T3.
;--
NxtObf: push p,t1 ; get a scratch
load. t1,NBHNxt,(t4) ; get next buffer pointer
jumpn t1,NxtOB1 ; there's one there, so go to it
pushj p,BufGet## ; allocate a buffer
pjrst tpopj## ; none available. take error return.
stor. t1,NBHNxt,(t4) ; link up to last buffer
movei t2,NbfByt ; make the previous buffer full
stor. t2,NBHCnt,(t4) ; ...
NxtOB1: move t4,t1 ; position for return
pjrst tpopj1## ; good return
subttl IPMake
;++
; Functional description:
;
; get a fresh buffer and put an IP leader (in 32 bit format)
; into it. then link the buffer to the beginning of the
; current output stream. then send this message down to
; 1822 level (IMPSER) to get it fired off.
;
;
; Calling sequence:
;
; move f,DDB
; pushj p,IpMake
; <always returns here>
;
; Input parameters:
;
; f - DDB for connection
;
; Output parameters:
;
; none.
;
; Implicit inputs:
;
; data in DDB
;
; Implicit outputs:
;
; data in DDB
;
; Routine value:
;
; none.
;
; Side effects:
;
; adds a buffer to the beginning of the current output stream.
;--
IpMake::
setzm IPOBuf+NBHLen ; clear first word of leader
move t1,[IPOBuf+NBHLen,,IPOBuf+NBHLen+1] ; set up blt pointer
blt t1,IPOBuf+IPLen+NBHLen-1; clear out leader.
movei t1,IPOBuf ; point at this header
exch t1,OBfFst(f) ; make us first and get old first.
stor. t1,NBHNxt,IpOBuf ; link old first to us.
movei t1,.IpVer ; load the version up
stor. t1,IpVers,NBHLen+IpOBuf ; store that in place
movei t2,IPLen ; get length (will need to compute
; this when we perform options.)
stor. t2,IPIHL,NBHLen+IpOBuf ; save that.
lsh t2,Wd2Byt ; convert from words to bytes
stor. t2,NBHCnt,IpOBuf ; save byte count for this buffer
move t1,t2 ; put in T1 (save T2 for checksumming)
addb t1,OBfByt(f) ; get a grand total in bytes.
stor. t1,IPTLen,NBHLen+IpOBuf ; save that in place
pushj p,GetID ; choose an ID for this message
stor. t1,IPID,NBHLen+IpOBuf ; and put it in the leader
movei t1,.IpTTL ; get the standard time to live
stor. t1,IpTTL,NBHLen+IpOBuf ; save that
move t1,Protcl(f) ; get next level protocol from DDB
stor. t1,IPProt,NBHLen+IpOBuf ; and save it
move t1,LclAdr(f) ; get our address
stor. t1,IPSA,NBHLen+IpOBuf ; save it.
move t1,RmtAdr(f) ; get his address
stor. t1,IPDA,NBHLen+IpOBuf ; and save it, too.
; one would add OPTIONS around here somewhere.
setz p3, ; clear checksum word
ifn FtChck,< ; doing checksums?
move t1,[point 16,NBHLen+IpOBuf]; point at the leader
; length in bytes is already in T2
pushj p,CSmWds## ; checksum them all
txc p3,msk.hw ; send one's complement of the sum
txnn p3,msk.hw ; if zero, make it...
movei p3,msk.hw ; ...the zero with all bits on
>
stor. p3,IpHChk,NBHLen+IpOBuf ; save it.
movei t1,.lnkip ; get our "link" number to tell
; 1822 level that that's who
; we are.
pjrst ImpMak## ; and call IMP level processing
; to send it off.
subttl GetID
;++
; Functional description:
;
; get an ID number for some outgoing IP message
;
;
; Calling sequence:
;
; pushj p,GetID
; <always returns here, ID in T1>
;
; Input parameters:
;
; none.
;
; Output parameters:
;
; T1 - an ID
;
; Implicit inputs:
;
; none.
;
; Implicit outputs:
;
; none.
;
; Routine value:
;
; none.
;
; Side effects:
;
; updates ID number so we don't get the same number twice.
;--
GetId: aos t1,LstID ; incr it and retrieve it.
popj p, ; and return
subttl ICMP message handling code
ICMPln==2 ; number of words in an ICMP leader.
ICMNLL==↑d8 ; number of bytes of the next level's leader with
; an ICMP reply message
$low ; define the storage needed
ICMPIB: block ICMPLn ; words needed for header
; the following block is used and removed under ScnOff.
ICMPOB: xwd ICMPLn*4,0 ; pseudo leader in case needed
block ICMPLn ; buffer for forming ICMP leaders
; for output.
NxtLBf: xwd ICMNLL,0 ; number of bytes here.
NxtLvl: block ICMNLL/4 ; space for 64 bit of leader
; for the next level protocol
; if needed for ICMP message.
$high ; back to protected code
ICMPPn: point 8,ICMPIB ; pointer to start loading the
; header block from the stream.
NxtLPn: point 8,NxtLvl ; pointer to storage area for
; "next level" leader.
; define the actual header fields. position is the bit position of the
; left most bit.
;
; name word position width
DefFd. ICMPTp, 0, 0, 8 ; type of message
DefFd. ICMPCd, 0, 8, 8 ; code field
DefFd. ICMPCs, 0, 16, 16 ; checksum
DefFd. ICMP2d, 1, 0, 36 ; second word, in case it
; should be zeroed.
DefFd. ICMPPt, 1, 0, 8 ; pointer (parameter problem message)
DefFd. ICMPGA, 1, 0, 32 ; gateway address (redirect message)
DefFd. ICMPID, 1, 0, 16 ; identifier (echo, time, info)
DefFd. ICMPSq, 1, 16, 16 ; sequence (echo, time, info)
; words in the data part of the leader.
DefFd. ICMPOT, 0, 0, 32 ; originate timestamp (time)
DefFd. ICMPRT, 1, 0, 32 ; receive timestamp (time)
DefFd. ICMPTT, 2, 0, 32 ; transmit timestamp (time)
; types of ICMP messages
.icEcR==↑d0 ; echo reply
.icDU==↑d3 ; destination unreachable
.idNU==↑d0 ; network unreachable
.idHU==↑d1 ; host unreachable
.idPlU==↑d2 ; protocol unreachable
.idPoU==↑d3 ; port unreachable
.idFNC==↑d4 ; fragments needed but can't fragment (DF set)
.idSRF==↑d5 ; source route failed.
.icSQ==↑d4 ; source quench
.icRed==↑d5 ; redirect
.icEch==↑d8 ; echo
.icTEx==↑d11 ; time exceeded
.itTTL==↑d0 ; time to live expired
.itFRT==↑d1 ; fragment reassembly time expired
.icPrm==↑d12 ; parameter problem
.icTim==↑d13 ; timestamp
.icTSR==↑d14 ; timestamp reply
.icInf==↑d15 ; information request
.icInR==↑d16 ; information reply
subttl ICMPIn - handle an incoming ICMP message
ICMPIn:
pushj p,MilTim## ; get time (in case timestamp)
movem t1,RcvTim ; save it
ifn FtChck,< ; checksumming
setz p3, ; start the checksumming at zero
>
move t1,ICMPPn ; get pointer to buffer space.
movei t2,ICMPLn*4 ; load the number of bytes to get.
pushj p,GetLed## ; get the leader and checksum it
jrst NoICLd ; not enough data for the IP leader.
setz p1, ; remember the lack of a data buffer.
move t1,MsgLen(f) ; get total IP length
subi t1,ICMPLn*4 ; subtract leaders info
jumple t1,NoData ; skip this if nothing to read
pushj p,GetMes## ; read in data
jrst WrgLen ; not enough data. wrong length
move p1,t1 ; remember the buffer stream
NoData:
ifn FtChck,< ; doing checksumming
load. t1,ICMPCS,ICMPIB ; get the checksum from the leader
jumpe t1,ICMPNC ; this guy doesn't do checksums
; bear in mind that the checksum we now have in P3 has, along with
; all the right stuff, its one's complement. therefore, what
; we really have is <checksum> + -<checksum>, which is 0.
; further, since <checksum> has some bit on (otherwise the
; sender isn't checksuming and we wouldn't be here), it can be
; shown that the brand of one's complement 0 we must have is
; the version with all 1's. if that's what we have, we're ok.
; if not, the checksum failed.
hrrzs p3 ; get just the checksum
caie p3,<1←↑d16>-1 ; magic, as explained above
jrst WrgChk ; checksum failed
ICMPNC: ; here to skip over the checksum checks because sender is not
; checksumming.
>
load. t1,ICMPTp,ICMPIB ; get type
cail t1,ICMCnt ; is it in the range we know?
jrst TypUnk ; no. count error, etc.
aos ICMTyp##(t1) ; count this ICMP message type
; for GETTABs.
jrst @ICMDis(t1) ; yes. dispatch to it.
subttl ICMP returns
NoICLd: aosa ICMNLd## ; not enough to get a leader
WrgLen: aos ICMDEr## ; IP length was shorter than
; data read in.
popj p, ; and return
WrgChk: aosa ICMChk## ; wrong checksum. count it.
TypUnk: aos ICMUnT## ; count unknown type
RelDat: hlrz t1,p1 ; get pointer at data
pjrst RelBuf## ; release buffers
subttl ICMP message type definitions
; dispatch vector for ICMP message types
ICMDis:
ICMEcR ;(0) echo reply
ICMUDf ;(1) undefined
ICMUDf ;(2) undefined
ICMCGT ;(3) destination unreachable (can't get there).
ICMSQ ;(4) source quench
ICMRed ;(5) redirect message
ICMUDf ;(6) undefined
ICMUDf ;(7) undefined
ICMEch ;(8) echo
ICMUDf ;(9) undefined
ICMUDf ;(10) undefined
ICMTEx ;(11) time exceeded
ICMPrm ;(12) parameter problems
ICMTim ;(13) timestamp
ICMTSR ;(14) timestamp reply
ICMInf ;(15) information request
ICMInR ;(16) information reply
ICMCnt==.-ICMDis ; number of types supported
ifg ICMCnt - ICMLen,< ; make sure NetSub has room to remember
; the number of message types we may
; have.
printx ? ICMLen (from NetDef.MAC) must be greater than or equal to ICMCnt
>
ICMUDf==RelDat ; do nothing for undefined messages
ICMEcR==RelDat ; don't send echo messages, so can't get a reply
ICMTSR==RelDat ; don't send timestamps, so ignore replies.
ICMInR==RelDat ; don't send info request messages, so can't get
; replies to them.
subttl handlers for different ICMP message types
; destination unreachable. update our tables
ICMCGT:
pushj p,ICMDDB ; get the DDB that fired off
; this message.
jrst RelDat ; i don't think i sent this mesage.
load. t1,ICMPCd,ICMPIB ; get the code that tells us
; what is is we can't reach.
txo t1,1b0 ; set sign bit to indicate failure
movem t1,State(f) ; and put in the state word
; (this makes the "state" change).
pushj p,ImpWak## ; wake up user so he notices.
jrst RelDat ; and return buffer and self
; source quench. try to cut down data rate.
ICMSQ: ; just ignore until we think of something clever to do.
jrst RelDat ; and return
; redirect. update all our DDBs that talk to this host so that NetAdr
; is as indicated.
ICMRed:
pushj p,ICMDDB ; get the DDB that sent this
jrst ICMRe1 ; not a DDB. do what we can
load. t1,ICMPGA,ICMPIB ; get the internet gateway address.
txz t1,NetMsk ; this guy claims it's on our network
movem t1,NetAdr(f) ; so use this.
pushj p,FixRTQ## ; correct anything we can in
; the retransmission queue.
ICMRe1: ; should update targetting tables
jrst RelDat ; and return
; echo. turn into an echo reply
ICMEch:
move t1,p1 ; point at data
movei t2,.icEcR ; type is echo reply
setz t3, ; code is 0
; here to copy the ID over and call ICMPMk. clobbers P3.
ICMCID: load. p3,ICMP2d,ICMPIB ; get ID, etc., from incoming
scnoff ; no interrupts allowed here
stor. p3,ICMP2d,ICMPOB+NBHLen ; and put it in outgoing.
pushj p,ICMPMk ; try to send it and return.
pjrst sonppj## ; interrupts on again and go
; time exceeded. probably can't do anything
ICMTEx:
jrst RelDat ; and return
; parameter problem. try to save info for later analysys.
ICMPrm:
jrst RelDat ; and return
; time stamp. create reply.
ICMTim:
move t1,RcvTim ; get time this packet was received
stor. t1,ICMPRT,NBHLen(p1) ; save in buffer
pushj p,MilTim## ; get millisecond time since midnight
stor. t1,ICMPTT,NBHLen(p1) ; save that as last time we saw it
move t1,p1 ; point at buffer
movei t2,.icTSR ; timestamp reply message
setz t3, ; code 0
jrst ICMCID ; set ID word and send it
; information request. supply answer
ICMInf:
move t1,RmtAdr(f) ; get address of incoming
txnn t1,NetMsk ; is there a network?
txo t1,ArpAdr ; no. set it
movem t1,RmtAdr(f) ; put back fully specified host.
move t1,IPAddr ; get my own site number
movem t1,LclAdr(f) ; make that our address
setzb t1,t3 ; no data to send, code 0
movei t2,.icInR ; type is info reply.
pushj p,ICMCID ; copy ID and send message
jrst RelDat ; return any errorneous data.
subttl ICMDDB
;++
; Functional description:
;
; look at an incoming ICMP message with a IP/TCP leader
; following it and track down the DDB this is aimed at.
;
;
; Calling sequence:
;
; move P1,<first buffer of IP/TCP leader>
; pushj p,ICMDDB
; <returns here is no such DDB exists>
; <here with DDB pointed to by F>
;
; Input parameters:
;
; P1 - pointer the the first buffer of the IP and TCP headers.
;
; Output parameters:
;
; F - pointer to DDB this message applies to.
;
; Implicit inputs:
;
; none.
;
; Implicit outputs:
;
; none.
;
; Routine value:
;
; returns non-skip if no such DDB exists.
;
; Side effects:
;
; none.
;--
ICMDDB: pushj p,save1## ; make sure P1 comes through ok.
load. t1,IPDA,NBHLen(p1) ; get the address the message
; was being sent to.
load. t4,IPProt,NBHLen(p1) ; and get the protocol being used.
load. t2,IpIHL,NBHLen(p1) ; get the length of the IP leader.
addi t2,StdPrt ; add on the offset to the port word.
; (this is zero, but might as
; well be complete.)
lsh t2,wd2byt ; convert to bytes
ICMDD1: load. t3,NBHCnt,(p1) ; get the byte count for this buffer
camge t2,t3 ; is there that much in this buffer?
jrst ICMDD2 ; yes. the TCP leader starts
; in this buffer.
sub t2,t3 ; remove that amount from the count.
load. p1,NBHNxt,(p1) ; link on to next buffer
jumpn p1,ICMDD1 ; loop if another buffer
popj p, ; else we couldn't find the DDB
; because there's an error in
; the ICMP message. clear
; stack and return.
ICMDD2: lsh t2,byt2wd ; covert back to word count
addi p1,NBHLen(t2) ; point at port word of next level's
; leader.
load. t2,StdDP,(p1) ; get the destination port.
load. t3,StdSP,(p1) ; and the port it was send from
; (our local port).
pjrst FndDDB## ; go try to find that DDB.
subttl ICMPMk
;++
; Functional description:
;
; prepare a ICMP message and call IP to send it.
;
;
; Calling sequence:
;
; move f,DDB
; move t1,<message data, or zero if no additional data>
; move t2,<ICMP message type>
; move t3,<ICMP message code>
; ScnOff
; pushj p,ICMPMk ; second word of ICMP leader
; ; (in ICMPOB) already setup
; <akways returns here>
;
; Input parameters:
;
; f - DDB for connection, usually a pseudo DDB since this is usually
; in response to an arrivign IP message.
; t1 - pointer to first βuffer in the data to be sent, or zero if
; no addtitional data is to be sent.
; t2 - ICMP message type for message
; t3 - ICMP code for message
;
; Output parameters:
;
; none.
;
; Implicit inputs:
;
; data in DDB
;
; Implicit outputs:
;
; data in DDB
;
; Routine value:
;
; none.
;
; Side effects:
;
; none.
;--
ICMPMk:
stor. t2,ICMPTp,ICMPOB+NBHLen ; store the type
stor. t3,ICMPCd,ICMPOB+NBHLen ; and the code
stor. t1,NBHNxt,ICMPOB ; link next buffer
movei t3,ICMPOB ; point at this leader space
movem t3,OBfFst(f) ; make this the first buffer.
setzb p3,OBfByt(f) ; clear checksum and byte count
stor. p3,ICMPCS,ICMPOB+NBHLen ; set checksum to zero in order
; to checksum (or to indicate
; that we aren't checksumming).
ifn FtChck,< ; if we're checksumming
ICMPCS: load. t2,NBHCnt,(t3) ; get the byte counts in this buffer
addm t2,OBfByt(f) ; increase byte count enough
move t1,[point 16,NBHLen(t3)] ; and point to data
pushj p,CSmWds## ; checksum this buffer
load. t3,NBHNxt,(t3) ; get next buffer in chain
jumpn t3,ICMPCS ; another buffer to do.
txc p3,msk.hw ; send one's complement of the sum
txnn p3,msk.hw ; if zero, make it...
movei p3,msk.hw ; ...the zero with all bits on
stor. p3,ICMPCS,ICMPOB+NBHLen ; set checksum correctly.
> ; end of IFN FtChchk
pushj p,OutPre## ; enough buffer space for message?
jrst ICMPFl ; no. forget it.
push p,Protcl(f) ; save protocol (can't think of
; an instance where this will
; be important, but be careful.)
movei t1,.ipicm ; load ICMP's protocol
movem t1,Protcl(f) ; make this the protocol
pushj p,IpMake ; link up and send
pop p,Protcl(f) ; restore old protocol
popj p, ; return to caller
ICMPFl: pop p,Protcl(f) ; restore old protocol
setz t1, ; clear first buffer pointer
exch t1,OBfFst(f) ; get/clear prepared stream
pushj p,RelBuf## ; flush it
popj p, ; go.
subttl RedSnd
;++
; Functional description:
;
; read in two words (first 64 bits of next level leader, if any),
; link to IP leader and send out an ICMP message with this as data.
;
;
; Calling sequence:
;
; move f,DDB
; move t1,<ICMP type>
; move t2,<ICMP code>
; move p4,<input byte getter>
; pushj p,RedSnd ; 2nd word of ICMP message already set
; or
; pusgj p,RedSn0 ; 2nd word of ICMP should be 0
; <always returns here>
;
; Input parameters:
;
; F - DDB
; T1 - type for ICMP message
; T2 - code for ICMP message
; P4 - coroutine for getting bytes from input stream.
;
; Output parameters:
;
; none.
;
; Implicit inputs:
;
; DDB, IPIBuf.
;
; Implicit outputs:
;
; none.
;
; Routine value:
;
; none.
;
; Side effects:
;
; tries to put an ICMP message on the output stream.
; read bytes from P4 bytes stream, possibly discarding buffer.
; clobbers P3.
;
;--
RedSn0: zero. ,ICMP2d,ICMPOB+NBHLen ; zero 2nd word of ICMP leader.
RedSnd:
push p,t1 ; save 1st arg
push p,t2 ; save 2nd arg
movei t1,ICMNLL ; length we need
move t2,NxtLPn ; pointer to storage for it
pushj p,GetLed## ; get the leader
jrst SndRs1 ; not enough bytes. make sure
; not to link up.
skipa t2,[IPIBHd] ; point at IP input ledaer buffer.
RedSnL: move t2,t1 ; save this buffer pointer
load. t1,NBHNxt,(t2) ; get next buffer
jumpn t1,RedSnL ; loop until no next buffer
movei t1,NxtLBf ; point at buffer for next
; level leader.
stor. t1,NBHNxt,(t2) ; link it up to this buffer
jrst SndRs1 ; go get args back from stack
; and send message off.
subttl CutSnd
;++
; Functional description:
;
; send an error response to some IP message with next level leader
; and message already read in. follows buffers
; connected to IP input leader to find next level protocol,
; cuts next level (TCP only at this writing) to only first
; 64 bits of leader, and sends an ICMP reply with these leaders
; as data.
;
;
; Calling sequence:
;
; move f,DDB
; move t1,<ICMP message type>
; move t2,<ICMP message code>
; pushj p,CutSnd ; second word of ICMP leader
; ; (in ICMPOB) already setup
; <always returns here>
;
; Input parameters:
;
; f - DDB
; T1 - type for ICMP message
; T2 - code for ICMP message
;
; Output parameters:
;
; none.
;
; Implicit inputs:
;
; 2nd word of ICMP blocks should be set as desired.
;
; Implicit outputs:
;
; none
;
; Routine value:
;
; none.
;
; Side effects:
;
; puts an ICMP message on the output queue.
; clobbers T1, T2, T3 and T4.
;--
CutSn0: zero. ,ICMP2d,ICMPOB+NBHLen ; clear second word of ICMP message
CutSnd: push p,t1 ; preserve arg
push p,t2 ; and arg
load. t1,IPIHL,IPIBuf ; get length of leader
lsh t1,wd2byt ; convert to bytes
addi t1,ICMNLL ; add in the amount we're supposed
; to provide from the next level.
movei t2,IPIBHd ; point at input stream
pushj p,SkpByt## ; skip those bytes
jumpe t2,SndRs1 ; not enough for next level leader
stor. t1,NBHCnt,(t2) ; set the count to the amount we
; needed from this buffer.
load. t1,NBHNxt,(t2) ; get next buffer in stream
zero. ,NBHNxt,(t2) ; clear that pointer
pushj p,RelBuf## ; discard the rest of the stream.
; here to point at IP leader and get args back from stack. called also
; from RedSnd.
SndRs1: movei t1,IPIBHd ; point at beginning of data
pop p,t3 ; get 2nd arg back (was in T2)
pop p,t2 ; get 1st arg back (was in T1)
pjrst ICMPMk ; send it and return
subttl SndNSP
;++
; Functional description:
;
; send a message to the sender of the current message saying
; "no such port".
;
;
; Calling sequence:
;
; move f,<ddb>
; pushj p,SndNSP
;
; Input parameters:
;
; F - DDB.
;
; Output parameters:
;
; none.
;
; Implicit inputs:
;
; DDB. IPIBuf.
;
; Implicit outputs:
;
; none.
;
; Routine value:
;
; none.
;
; Side effects:
;
; tries to put a no such port ICMP message on the output queue.
;--
SndNSP::
setzm IpOptn ; we may flush incoming IP options
; when we build ICMP message, so
; make sure to clear the pointer.
movei t1,.icDU ; destination unreachable type
movei t2,.idPoU ; port unreachable code
pjrst CutSn0 ; fire off the response.
subttl data storage area
$low
FstFdb: 0 ; first FDB in system chain.
LstId: 0 ; last IP ID given.
RcvTim: 0 ; time the latest ICMP message was received.
IpOptn: 0 ; incoming IP options point if option buffers
; have not yet been deleted.
IpPDDB=.-PDBTop ; define hypothetical start of our pseudo DDB
block PDBBot-PDBTop+1 ; number of words we really use
$high
$lit
end